
import rcontrolutil
import rcontrol
import Tkinter



class RInput(rcontrol.RControl):
	"""
	Properties:
	
	*text* - String. Current contents of the input.
	*bgcolor* - Background color of the input. RGB triplet, such as (255,0,0) for pure red.
	*color* - Foreground color of the input. RGB triplet.
	*borderwidth* - An integer, width of border in pixels.
	*font* - Set font of input. Standard tkinter font format, such as ('Times New Roman', 12, 'normal')
	*alignment* - Set alignment of text. One of 'left','right','center'.
	*borderstyle* - Border style. One of 'sunken','raised','groove','ridge','flat'. Default is 'sunken'.
	
	*selectioncolor* - Color of selected text. RGB triplet.
	*selectionbgcolor* - Background color of selected text. RGB triplet.
	*password* - True or false. Set to True to display all characters as *.
	
	*width* - Set width of input, where one unit is the width of a char. Default is 20.
	
	*enabled* -  If False, the input is disabled.
	*readonly* - If True, the input is read only, but text can still be selected and copied. Has no visible effect if disabled (enabled is false).
	"""
	
	_enabled=True
	_readonly=False
	_basecontrol = None
	
	def __init__(self, strDefaultText='', parent=None, **options):
		self._newWidgetManual(parent, Tkinter.Entry)
		
		if strDefaultText!='': self.text=strDefaultText
		self.set_many(**options)
	
	
	def scrollto_start(self):
		"""Scroll to the start of the input field."""
		self._basecontrol.xview(0)
	
	def scrollto_end(self):
		"""Scroll to the end of the input field."""
		self._basecontrol.xview(Tkinter.END)
	
	def get_selected_text(self):
		"""Return the text that is selected. "" (empty string) if there is no selection."""
		if self._basecontrol.selection_present():
			lower = min(self._basecontrol.index(Tkinter.ANCHOR), self._basecontrol.index(Tkinter.INSERT))
			upper = max(self._basecontrol.index(Tkinter.ANCHOR), self._basecontrol.index(Tkinter.INSERT))
			return self._basecontrol.get()[lower:upper]
		else:
			return ''
			
	def get_selection(self):
		"""Return the indices of the selection. Use get_selected_text to retrieve the actual text. Position of cursor if there is no selection."""
		if self._basecontrol.selection_present():
			lower = min(self._basecontrol.index(Tkinter.ANCHOR), self._basecontrol.index(Tkinter.INSERT))
			upper = max(self._basecontrol.index(Tkinter.ANCHOR), self._basecontrol.index(Tkinter.INSERT))
			return (lower, upper)
		else:
			insert = self._basecontrol.index(Tkinter.INSERT)
			return (insert, insert)
	
	def select_all_binding(self):
		"""Add Ctrl+A -> select all binding"""
		def sel(self):
			self.select_all()
			return 'break'
		self.bind('<Control-a>',lambda event: sel(self), '+')
	
	def select_all(self):
		"""Select all text in the input."""
		self.select_range(0,Tkinter.END)
	
	def select_range(self, start, stop=Tkinter.END):
		"""Select range of text in the input."""
		# Don't use selection_range because for some reason Tkinter doesn't set the flags correctly
		self._basecontrol.selection_from(start)
		self._basecontrol.selection_to(stop)
		#For some reason, tkinter doesn't also set the insertion cursor.
		self._basecontrol.icursor(stop)
	def deselect(self):
		"""Deselect any selection in the input"""
		self._basecontrol.selection_clear()
	
	def delete_text(self, start, stop=Tkinter.END):
		"""Delete range of text."""
		self._basecontrol.delete(start, stop)
	
	def clear(self):
		"""Delete all text."""
		self._basecontrol.delete(0, Tkinter.END)
	
	
	#todo: validation? useful feature? apparently a bug in this, see djinput.py
	#~ def enable_validation(self, validate, whenValidate='all', fnInvalid=None):
		#~ """Add validation to only allow certain characters in the input field. validate can either be the string 'numeric', a string in the form 'maxlength:3', or a custom function returning True or False. The custom function should take a string as an argument. whenValidate is one of 'focus','focusin','focusout','all','none'. If whenValidate is at focus, you will want to provide a fnInvalid function that will be called if the value is not valid. Use disable_validation to disable validation."""
		#~ if isinstance(validate, str):
			#~ if validate.startswith('maxlength:'):
				#~ nMaxLength = int(validate[len('maxlength:'):])
				#~ def fnValidate(s, maxLength=nMaxLength):
					#~ return len(s) <= maxLength
			#~ elif validate=='numeric':
				#~ def fnValidate(s):
					#~ for c in s:
						#~ if c not in '0123456789.':
							#~ return False
					#~ return True
			#~ else:
				#~ raise RuntimeError, 'Validate must either be custom function, the string "numeric", or a string in the form "maxlength:3"'
		#~ else:
			#~ fnValidate = validate #We were (in theory) passed a custom function
		#~ if fnInvalid: self._basecontrol.config(invalidcommand=fnInvalid)
		#~ # Test to check if the function accepts the correct number of arguments.
		#~ fnValidate('test')
		#~ # This is kind of tricky. This registers the function with Tkinter so that it performs variable subsitution.
		#~ # See http://mail.python.org/pipermail/tkinter-discuss/2006-August/000863.html
		#~ fnValidate = (self._basecontrol.register(fnValidate), '%P')
		#~ self._basecontrol.config(validatecommand=fnValidate, validate=whenValidate)
	#~ def disable_validation(self):
		#~ """Turn off validation for the input field."""
		#~ self._basecontrol.config(validate = 'none')

	def property_text_get(self):
		return self._basecontrol.get()
	def property_text_set(self, value):
		prevstate = self._basecontrol['state']
		self._basecontrol['state'] = Tkinter.NORMAL #according to docs calls to insert() or delete() ignored when state is readonly
		self._basecontrol.delete(0, Tkinter.END)
		self._basecontrol.insert(Tkinter.END, value)
		self._basecontrol['state'] = prevstate
		
	
	def property_password_get(self):
		if self._basecontrol['show']: return True
		else: return False
	def property_password_set(self, value):
		if value: self._basecontrol['show']='*' 
		else: self._basecontrol['show']=''
	


	def property_readonly_get(self):
		return self._readonly
	def property_readonly_set(self, value):
		if value: 
			self._readonly = True
			self._basecontrol['readonlybackground'] ='SystemWindow'
			if self._enabled: self._basecontrol['state']=Tkinter.NORMAL
			else: self._basecontrol['state']=Tkinter.DISABLED
		else: 
			self._readonly = False
			if self._enabled: self._basecontrol['state']='readonly'
			else: self._basecontrol['state']=Tkinter.DISABLED
	
	def property_enabled_get(self):
		return self._enabled
	def property_enabled_set(self, value):
		if value: 
			self._enabled = True
			if self._readonly: self._basecontrol['state']='readonly'
			else: self._basecontrol['state']=Tkinter.NORMAL
		else: 
			self._enabled = False
			self._basecontrol['state']=Tkinter.DISABLED

	_properties = {
		'password': (property_password_get,property_password_set),
		'text': (property_text_get,property_text_set),
		'enabled': (property_enabled_get,property_enabled_set),
		'readonly': (property_readonly_get,property_readonly_set),
			
			
		'bgcolor': ('background',rcontrolutil.mapColor),
		'color': ('foreground',rcontrolutil.mapColor),
		'selectioncolor': ('selectforeground',rcontrolutil.mapColor),
		'selectionbgcolor': ('selectbackground',rcontrolutil.mapColor),
		'borderwidth': 'borderwidth',
		'font': 'font',
		'alignment': ('justify', rcontrolutil.mapAlignment),
		'borderstyle': ('relief',rcontrolutil.mapBorderstyle),
		'width': 'width',
	
		}




